// This file is part of OpenMeca, an easy software to do mechanical simulation.
//
// Author(s)    :  - Damien ANDRE  <openmeca@gmail.com>
//
// Copyright (C) 2012 Damien ANDRE
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.


#include <cassert>
#include <QFileDialog>
#include <QMessageBox>
#include <QCloseEvent>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>


#include "OpenMeca/Gui/MainWindow.hpp"
#include "OpenMeca/Gui/Dialog.hpp"
#include "OpenMeca/Core/CommonProperty.hpp"
#include "OpenMeca/Item/Body.hpp"
#include "OpenMeca/Item/Link.hpp"
#include "OpenMeca/Item/LinkList.hpp"
#include "OpenMeca/Item/PartLink.hpp"
#include "OpenMeca/Item/PartUserPoint.hpp"
#include "OpenMeca/Item/PartUserPipe.hpp"
#include "OpenMeca/GlobalSetting/MenuManager.hpp"
#include "OpenMeca/GlobalSetting/UnitManager.hpp"
#include "OpenMeca/Core/System.hpp"

namespace OpenMeca
{
  namespace Gui
  {
  
    MainWindow* MainWindow::me_ = 0;

    MainWindow& 
    MainWindow::Get()
    {
      assert(me_!=0);
      return *me_;
    }

    MainWindow::MainWindow(QWidget * parent)
      :QMainWindow(parent),
       currentDialog_(0),
       userActions_(),
       currentFileName_(),
       iconSize_(24),
       scalePart_(new WidgetScale(this, Core::System::Get().GetSettings().GetScalePart(), "Part Scale"))
    {

      assert(iconSize_ > 0);
      assert(me_==0);
      me_ = this;
      setupUi(this);
      treeView_->setIconSize(QSize(iconSize_,iconSize_));
      treeView_->setAutoScrollMargin(iconSize_);

      toolBar_->addWidget(scalePart_);


      Item::PartUserPipe::Init();
      Item::PartUserPoint::Init();

      Item::Body::Init();
      Item::LinkBase::Init();
      Item::Link<Item::Revolute>::Init();
      Item::PartLink<Item::Revolute,1>::Init();
      Item::PartLink<Item::Revolute,2>::Init();
      GlobalSetting::MenuManager::Init();
      GlobalSetting::UnitManager::Init();

      QObject::connect(actionUndo, SIGNAL(triggered()), this, SLOT(Undo()));
      QObject::connect(actionRedo, SIGNAL(triggered()), this, SLOT(Redo()));
      QObject::connect(actionSaveAs, SIGNAL(triggered()), this, SLOT(SaveAs()));
      QObject::connect(actionSave, SIGNAL(triggered()), this, SLOT(Save()));
      QObject::connect(actionLoad, SIGNAL(triggered()), this, SLOT(Load()));
      QObject::connect(actionQuit, SIGNAL(triggered()), this, SLOT(close()));
      UpdateHistoric();
    }
  
    MainWindow::~MainWindow()
    {
      Core::System::Quit();
    }


    TreeView& 
    MainWindow::GetTreeView()
    {
      return *treeView_;
    }

    const TreeView& 
    MainWindow::GetTreeView() const
    {
      return *treeView_;
    }

    Viewer& 
    MainWindow::GetViewer()
    {
      return *viewer_;
    }

    const Viewer& 
    MainWindow::GetViewer() const
    {
      return *viewer_;
    }



    int
    MainWindow::GetIconSize()
    {
      return iconSize_;
    }


    void
    MainWindow::AddGlobalSetting(Core::GlobalSetting& globalSetting)
    {
      globalSet_.AddItem(globalSetting);
    }
    
    void
    MainWindow::RemoveGlobalSetting(Core::GlobalSetting& globalSetting)
    {
      globalSet_.RemoveItem(globalSetting);
    }

    void
    MainWindow::DialogContainerIsBusy(Dialog& dial)
    {
      if (currentDialog_!=0)
	{
	  toolBox_->removeItem (1);
	  currentDialog_->Cancel();
	}
      assert(currentDialog_ ==0);
      currentDialog_ = &dial;
      
    }

    void
    MainWindow::DialogContainerIsFree(Dialog& dial)
    {
      assert(currentDialog_ == &dial);
      currentDialog_ = 0;
      toolBox_->removeItem (1);
      toolBox_->setCurrentIndex(0);
    }

    QToolBox&
    MainWindow::GetDialogContainer()
    {
      return *toolBox_;
    }

    void
    MainWindow::AddToHistoric(QAction& action)
    {
      userActions_.push_back(&action);
      UpdateHistoric();
    }

    void 
    MainWindow::Undo()
    {
      std::cout << "MainWindow::Undo" << std::endl;
      Core::System::Get().GetHistoric().LoadPreviousState();
      UpdateHistoric();
    }

    void 
    MainWindow::Redo()
    {
      std::cout << "MainWindow::Redo" << std::endl;
      Core::System::Get().GetHistoric().LoadNextState();
      UpdateHistoric();
    }

    
    void 
    MainWindow::UpdateHistoric()
    {
      const bool undo = Core::System::Get().GetHistoric().IsUndoPossible();
      const bool redo = Core::System::Get().GetHistoric().IsRedoPossible();
      actionUndo->setEnabled(undo);
      actionRedo->setEnabled(redo);
    }

    
    void 
    MainWindow::SaveAs()
    {
      
      //the qt QFileDialog::getSaveFileName static method don't manage suffix
      //it's boring
      QFileDialog fileDialog(this, tr("Save As"));
      fileDialog.setFilter (tr("OpenMeca Files (*.omc)"));
      fileDialog.setDefaultSuffix ("omc");
      fileDialog.setFileMode(QFileDialog::AnyFile);
      fileDialog.setAcceptMode(QFileDialog::AcceptSave);
      QString fileName;
      if (fileDialog.exec()) 
	{ 
	  QStringList fileNames = fileDialog.selectedFiles(); 
	  if ( fileNames.count() ) 
	    fileName = fileNames.at(0); 
	}

      
      if (!fileName.isEmpty())
	{
	  assert(fileName.endsWith(".omc"));
	  currentFileName_ = fileName.toStdString();
	  Save();
	}
    }

    
    void 
    MainWindow::Save()
    {
      if (currentFileName_.empty())
	{
	  SaveAs();
	  return;
	}
      QString qfileNameStr = currentFileName_.c_str();
      assert(qfileNameStr.endsWith(".omc"));
      Core::System::Get().SaveFile(currentFileName_);
    }
    
    
    void 
    MainWindow::Load()
    {
      //Todo check if system is edited
      QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"", tr("OpenMeca Files (*.omc)"));
      if (!fileName.isEmpty())
	{
	  currentFileName_ = fileName.toStdString();
	  Core::System::Get().LoadFile(currentFileName_);
	  UpdateHistoric();
	}
     
    }


    void 
    MainWindow::closeEvent(QCloseEvent* event)
    {
      std::cout << "MainWindow::closeEvent" << std::endl;
      if (Core::System::Get().IsEdited())
	{
	  QMessageBox msgBox;
	  msgBox.setText(tr("The document has been modified."));
	  msgBox.setInformativeText(tr("Do you want to save your changes?"));
	  msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
	  msgBox.setDefaultButton(QMessageBox::Save);
	  int ret = msgBox.exec();
	  switch (ret) 
	  {
	  case QMessageBox::Save:
	    event->accept();
	    Save();
	    break;
	  case QMessageBox::Discard:
	    event->accept();
	    break;
	  case QMessageBox::Cancel:
	    event->ignore();
	    break;
	  default:
	    assert(0);
	    break;
	  }
	}
    }
    
    
  
  }
}
